﻿using Consul;
using Microsoft.AspNetCore.Builder;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace Zore.App.Core.Consul
{
    public static class ConsulSign
    {
        private static IConfiguration _IConfiguration;

        private static string _ServiceID;

        private static ConsulConfig _ConsulConfig;

        private static ConsulClientConfiguration _ConsulClientConfiguration;

        /// <summary>
        /// consul配置
        /// </summary>
        public class ConsulConfig
        {
            /// <summary>
            /// 是否注册,默认true
            /// </summary>
            public bool Active { get; set; } = true;
            /// <summary>
            /// http or https,默认http
            /// </summary>
            public string Scheme { get; set; }="http";

            /// <summary>
            /// Consul数据中心,默认dc1
            /// </summary>
            public string Datacenter { get; set; }="dc1";
            /// <summary>
            /// Consul的IP地址,默认“http://127.0.0.1:8500”
            /// </summary>
            public Uri ConsulIP { get; set; }=new Uri("http://127.0.0.1:8500");
            /// <summary>
            /// 注册的服务名称,默认“DemoService”
            /// </summary>
            public string ServiceName { get; set; }="DemoService";

            /// <summary>
            /// 当前服务的IP地址,默认“127.0.0.1”
            /// </summary>
            public string Address { get; set; } = "127.0.0.1";
            
            /// <summary>
            /// 健康检查地址，默认“/health”
            /// </summary>
            public string HealthCheck { get; set; }="/health";

            /// <summary>
            /// 服务端口,默认80
            /// </summary>
            public int Port { get; set; }=80;

            public ConsulConfig(IConfiguration configuration)
            {
                //根据配置文件初始化Consul配置
                Active = Convert.ToBoolean(configuration["Consul:Active"]);
                Scheme = configuration["Consul:Scheme"];
                ConsulIP = new Uri(configuration["Consul:ConsulIP"]);
                ServiceName = configuration["Consul:ServiceName"];
                Address = configuration["Consul:Address"];
                HealthCheck = configuration["Consul:HealthCheck"];
                Port = int.Parse(configuration["Consul:Port"]);
                Datacenter = configuration["Consul:Datacenter"];
            }
        }


        /// <summary>
        /// 注册Consul
        /// </summary>
        /// <param name="app"></param>
        /// <param name="hostApplicationLifetime"></param>
        /// <param name="configuration"></param>
        public static void AddConsul(this IApplicationBuilder app, IHostApplicationLifetime hostApplicationLifetime, IConfiguration configuration)
        {

            _IConfiguration = configuration;

            if (Register())
            {
                hostApplicationLifetime.ApplicationStopped.Register(() =>
                {
                    using (var client = new ConsulClient(_ConsulClientConfiguration))
                    {
                        //注销服务
                        client.Agent.ServiceDeregister(_ServiceID).Wait();
                    }
                });
            }
        }

        /// <summary>
        /// 注册具体方法
        /// </summary>
        private static bool Register()
        {
            var result = true;
            _ConsulConfig = new ConsulConfig(_IConfiguration);
            try
            {
                if (!_ConsulConfig.Active)
                {
                    return false;
                }

                _ServiceID = $"{_ConsulConfig.ServiceName}-{_ConsulConfig.Port}";


                _ConsulClientConfiguration = new ConsulClientConfiguration() { Address = _ConsulConfig.ConsulIP, Datacenter = _ConsulConfig.Datacenter };

                using (var client = new ConsulClient(_ConsulClientConfiguration))
                {
                    //注册服务到Consul
                    client.Agent.ServiceRegister(new AgentServiceRegistration()
                    {
                        ID = _ServiceID, //服务编号，不能重复

                        Name = _ConsulConfig.ServiceName, //服务名字

                        Address = _ConsulConfig.Address,//urls.Split(":")[1].Trim('/'),//服务提供者的能被服务消费者访问的IP地址（可以被其他应用访问的地址，本机测试使用127.0.0.1，但在实际生产环境上一定要使用内网IP地址）

                        Port = _ConsulConfig.Port, //服务提供者的能被服务消费者访问的端口

                        Check = new AgentServiceCheck

                        {
                            DeregisterCriticalServiceAfter = TimeSpan.FromSeconds(5), //服务停止多久后反注册

                            Interval = TimeSpan.FromSeconds(10), //健康检查时间间隔，或者称为心跳

                            HTTP = $"{_ConsulConfig.Scheme}://{_ConsulConfig.Address}:{_ConsulConfig.Port}{_ConsulConfig.HealthCheck}", //健康检查地址

                            Timeout = TimeSpan.FromSeconds(5)
                        }

                    }).Wait(); //Consul客户端的所有方法几乎都是异步方法，但是都没有按照规范加上Async后缀，所以容易误导，记得调用后要Wait()或者await
                    Console.WriteLine("Consul注册成功");
                }
            }
            catch (Exception ex)
            {
                result = false;

                Console.WriteLine(ex.Message);
            }
            return result;
        }
    }
}
